package engine;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;


/**
 * Game.java
 * 
 * The Game class runs the application and all of its administrative duties: it
 * controls the framerate, updates the characters, level and playstate, as well
 * as invokes Camera
 * s method at regular intervals.
 * 
 * @author Connor Gordon, Niel Lebeck
 * 
 */
public class Game extends JPanel implements Runnable {
    //Default Screen Width & Heigh
    public static final int SCREEN_WIDTH = 640;
    public static final int SCREEN_HEIGHT = 480;
    //Default thread delay
    public static final int SLEEP_DELAY = 33;

    private Level myLevel;
    private LevelManager myLevelManager;
    private Camera myCamera;
    private Thread myAnimator;

    /**
     * @param lm LevelManager object which controls level order and traversal
     * @param c Camera object in charge of displaying each level
     */
    public Game (LevelManager lm, Camera c) {
        myCamera = c;
        myLevelManager = lm;
        myLevel = myLevelManager.getNextLevel(PlayState.START);
        myCamera.setLevel(myLevel);
        addKeyListener(new KeyListener());
        setFocusable(true);
        c.setScreenDimensions(getPreferredSize());
        myAnimator = new Thread(this);
        myAnimator.start();
    }

    /**
     * Returns preferred Default dimensions of the Screen
     * 
     * @return preferred screen dimensions
     */
    @Override
    public Dimension getPreferredSize () {
        return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
    }

    /**
     * Updates the game's play state
     */
    public void update () {
        PlayState currentState = myLevel.getPlayState();
        if (currentState != PlayState.IS_PLAYING) {
            myLevel = myLevelManager.getNextLevel(currentState);
            myCamera.setLevel(myLevel);
        }
        myLevel.updateCharacters();
    }

    /**
     * Paints the Game
     * 
     * @param g Graphics painting object
     */
    @Override
    public void paintComponent (Graphics g) {
        myCamera.paintGame(g);
    }

    /**
     * Runs the game at a constant framerate
     * Calls update and repaint at regular intervals
     */
    @Override
    public void run () {
        long beforeTime, timeDiff, sleepTime;
        beforeTime = System.currentTimeMillis();

        while (true) {
            update();
            repaint();

            // maintain constant frame rate by sleeping
            timeDiff = System.currentTimeMillis() - beforeTime;
            sleepTime = SLEEP_DELAY - timeDiff;
            if (sleepTime < 0) {
                sleepTime = 2;
            }
            try {
                Thread.sleep(sleepTime);
            }
            catch (InterruptedException e) {
                System.out.println("interrupted!");
            }
            beforeTime = System.currentTimeMillis();
        }
    }

    /**
     * Listens to keyboard input, and passes it to the Level class
     * 
     * @author Connor Gordon
     */
    private class KeyListener extends KeyAdapter {
        @Override
        public void keyReleased (KeyEvent e) {
            myLevel.keyReleased(e);
        }

        @Override
        public void keyPressed (KeyEvent e) {
            myLevel.keyPressed(e);
        }
    }
}
